using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Weight.Base;

namespace  RFCard
{
   public  class ICDevice : ICard
    {
        #region

        [DllImport("mwrf32.dll", EntryPoint = "rf_init", SetLastError = true,
               CharSet = CharSet.Auto, ExactSpelling = false,
               CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr rf_init(Int16 port, int baud);

        [DllImport("mwrf32.dll", EntryPoint = "rf_exit", SetLastError = true,
               CharSet = CharSet.Auto, ExactSpelling = false,
               CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_exit(IntPtr icdev);

        [DllImport("mwrf32.dll", EntryPoint = "rf_beep", SetLastError = true,
               CharSet = CharSet.Auto, ExactSpelling = false,
               CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_beep(IntPtr icdev, int msec);

        [DllImport("mwrf32.dll", EntryPoint = "rf_get_status", SetLastError = true,
              CharSet = CharSet.Auto, ExactSpelling = false,
              CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_get_status(IntPtr icdev, byte[] state);

        [DllImport("mwrf32.dll", EntryPoint = "rf_load_key", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_load_key(IntPtr icdev, byte mode, byte secnr, byte[] keybuff);

        [DllImport("mwrf32.dll", EntryPoint = "rf_load_key_hex", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_load_key_hex(IntPtr icdev, byte mode, byte secnr, byte[] keybuff);


        [DllImport("mwrf32.dll", EntryPoint = "a_hex", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 a_hex(byte[] asc, byte[] hex, Int16 len);

        [DllImport("mwrf32.dll", EntryPoint = "hex_a", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 hex_a(byte[] hex, byte[] asc, Int16 len);

        [DllImport("mwrf32.dll", EntryPoint = "rf_reset", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_reset(IntPtr icdev, Int16 msec);

        [DllImport("mwrf32.dll", EntryPoint = "rf_request", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_request(IntPtr icdev, byte mode, out UInt16 tagtype);


        [DllImport("mwrf32.dll", EntryPoint = "rf_anticoll", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_anticoll(IntPtr icdev, byte bcnt, out UInt32 snr);

        [DllImport("mwrf32.dll", EntryPoint = "rf_select", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_select(IntPtr icdev, UInt32 snr, out byte size);

        [DllImport("mwrf32.dll", EntryPoint = "rf_card", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_card(IntPtr icdev, byte mode, byte[] snr); //这里将第三个参数设置为byte数组，以便直接返回16进制卡号
        //public static extern Int16 rf_card(IntPtr icdev, int mode, out UInt32 snr);

        [DllImport("mwrf32.dll", EntryPoint = "rf_authentication", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_authentication(IntPtr icdev, byte mode, byte secnr);

        [DllImport("mwrf32.dll", EntryPoint = "rf_authentication_2", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_authentication_2(IntPtr icdev, byte mode, byte keynr, byte blocknr);

        [DllImport("mwrf32.dll", EntryPoint = "rf_read", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_read(IntPtr icdev, byte blocknr, byte[] databuff);

        [DllImport("mwrf32.dll", EntryPoint = "rf_read_hex", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_read_hex(IntPtr icdev, byte blocknr, byte[] databuff);

        [DllImport("mwrf32.dll", EntryPoint = "rf_write_hex", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_write_hex(IntPtr icdev, int blocknr, byte[] databuff);

        [DllImport("mwrf32.dll", EntryPoint = "rf_write", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_write(IntPtr icdev, byte blocknr, byte[] databuff);

        [DllImport("mwrf32.dll", EntryPoint = "rf_halt", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_halt(IntPtr icdev);

        [DllImport("mwrf32.dll", EntryPoint = "rf_changeb3", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_changeb3(IntPtr icdev, byte sector, byte[] keya, byte B0, byte B1,
              byte B2, byte B3, byte Bk, byte[] keyb);

        [DllImport("mwrf32.dll", EntryPoint = "rf_pro_rst", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_pro_rst(IntPtr icdev, byte[] _Data);

        [DllImport("mwrf32.dll", EntryPoint = "rf_pro_trn", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_pro_trn(IntPtr icdev, byte[] problock, byte[] recv);

        [DllImport("mwrf32.dll", EntryPoint = "rf_ctl_mode", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_ctl_mode(IntPtr icdev, byte mode);    //受控方式

        [DllImport("mwrf32.dll")]
        public static extern Int16 rf_setbright(IntPtr icdev, byte bright);

        [DllImport("mwrf32.dll")]
        public static extern Int16 rf_disp_mode(IntPtr icdev, byte mode);

        [DllImport("mwrf32.dll")]
        public static extern Int16 rf_settime(IntPtr icdev, byte[] time);

        [DllImport("mwrf32.dll", EntryPoint = "rf_ctl_mode", SetLastError = true,
            CharSet = CharSet.Ansi, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_settimehex(IntPtr icdev, string time);


        [DllImport("mwrf32.dll", EntryPoint = "rf_CtlBackLight", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_CtlBackLight(IntPtr icdev, byte cOpenFlag); //控制背光

        [DllImport("mwrf32.dll", EntryPoint = "rf_LcdClrScrn", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_LcdClrScrn(IntPtr icdev, byte cLine);   //清LCD屏

        [DllImport("mwrf32.dll", EntryPoint = "rf_DispMainMenu", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_DispMainMenu(IntPtr icdev);     //显示欢迎光临

        [DllImport("mwrf32.dll", EntryPoint = "rf_DispLcd", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_DispLcd(IntPtr icdev, byte line, byte type);   //显示系统内置操作

        [DllImport("mwrf32.dll", EntryPoint = "rf_DispInfo", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_DispInfo(IntPtr icdev, byte line, byte offset, byte[] data);  //显示信息，操作前需清屏

        [DllImport("mwrf32.dll", EntryPoint = "rf_disp8", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_disp8(IntPtr icdev, Int16 disp_len, byte[] disp_str);  //在读写器数码管上显示数字
        #endregion

        public IntPtr icdev = IntPtr.Zero; //设备号
        public byte[] snr = new byte[5];  //卡片序列号
        public static Encoding mEncode = Encoding.GetEncoding("GB2312");//编码方式
        private List<string> mComparison =null;

        //初始化
        public ResultEntity Init()
        {
            PreRfCardNo = string.Empty;
            ResultEntity res = ResultEntity.Success("IC 卡设备不需要初始化!");
            return res;
        }

        /// <summary>
        /// 打开设备
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        ResultEntity ICard.Open(OpenEntity entity)
        {
            ResultEntity res = ResultEntity.Default();
            PreRfCardNo = string.Empty;
            try
            {
                short port = Convert.ToInt16( entity.Port - 1);
                //打开串口
                icdev = rf_init(port, entity.BaudRate);
                if (icdev.ToInt32() > 0)
                {
                    rf_beep(icdev, 25);
                }
                else
                {
                    return ResultEntity.Error("IC卡设备 打开串口失败!");
                }

                //为每个扇区加载密码
                byte[] key = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
                byte mode = 0; //0 - 2 表示A密码
                for (byte sector = 0; sector < 16; sector++)
                {  
                    short st = rf_load_key(icdev, mode, sector, key);
                    if (st != 0)
                    {
                        string s1 = Convert.ToString(sector);
                        res = ResultEntity.Error("装载读卡器密码错误,扇区号:"+s1);
                        return res;
                    }
                }
                return  ResultEntity.Success("IC卡设备 打开串口成功!");
            }
            catch (Exception ex)
            {
                return ResultEntity.Error("IC卡设备 打开串口异常，异常内容:"+ex.Message+","+ex.StackTrace);
            }
        }

        /// <summary>
        /// 获取设备信息
        /// </summary>
        /// <returns></returns>

        public ResultEntity GetDeviceInfo()
        {
            StringBuilder contentBuider = new StringBuilder("厂商:明华读卡器\r\n\r\n");
            contentBuider.Append("型号:RF-35 \r\n\r\n");
            contentBuider.Append("依赖库:mwrf32.dll \r\n\r\n");
            contentBuider.Append("说明: 公司使用的是M1卡，分为16个扇区，每个扇区为4块，每块16个字，以块为存储单位;其中 ");
            contentBuider.Append("第0扇区的块0 用于存放厂商代码，已固化，不能修改。其它各扇区的块0、块1、块2用于存储数据，块3是")
                .Append("控制块，存放密码A、存储控制、密码B");
            return ResultEntity.Success(contentBuider.ToString());
        } 

        /// <summary>
        /// 关闭设备
        /// </summary>
        /// <returns></returns>
        ResultEntity ICard.Close()
        {
            var rs = ResultEntity.Default();
            try
            {
                if(icdev == IntPtr.Zero)
                {
                    return ResultEntity.Success("IC卡设备 没有打开的设备不需要关闭!");
                }
                short st = rf_exit(icdev);
                if (st == 0)
                {
                    return ResultEntity.Success("IC卡设备 关闭成功!");
                }
                else
                {
                    return ResultEntity.Error("IC卡设备 关闭失败!");
                }
            }
            catch (Exception ex)
            {
                return ResultEntity.Error("IC卡设备 关闭异常,异常内容:"+ex.Message+","+ex.StackTrace);
            }
        }

        /// <summary>
        /// 上一个卡号
        /// </summary>
        private string PreRfCardNo = string.Empty;
        /// <summary>
        /// 获取卡号
        /// </summary>
        /// <returns></returns>
        ResultEntity<ResultValEntity> ICard.GetCardNo()
        {
            ResultValEntity entity = new ResultValEntity();
            ResultEntity<ResultValEntity> result = ResultEntity<ResultValEntity>.Default(entity, "");
            try
            {
                short val = rf_card(icdev, (byte)1, snr);
                if (val != 0)
                {
                    PreRfCardNo = string.Empty;
                    result = ResultEntity<ResultValEntity>.Error(entity,"IC卡设备 获取卡号失败,错误:" + val);
                }
                else
                {
                    byte[] snr1 = new byte[8];
                    hex_a(snr, snr1, 4); //将卡号转换为16进制字符串
                    string value = System.Text.Encoding.Default.GetString(snr1);
                    string content = Convert.ToString( Convert.ToInt64(value, 16));
                    entity.val = getLimitCarNo(content);
                    if (PreRfCardNo != entity.val)
                    {
                        rf_beep(icdev, 25);
                        PreRfCardNo = entity.val;
                    }
                    result = ResultEntity<ResultValEntity>.Success(entity, entity.val);
                }
            }
            catch (Exception ex)
            {
                result = ResultEntity<ResultValEntity>.Error(entity, "IC卡设备 获取卡号异常,异常信息:" + ex.Message + "," + ex.StackTrace);

            }

            return result;
        }

        /// <summary>
        /// 返回匹配卡号
        /// </summary>
        /// <param name="cardNo">IC 卡号</param>
        /// <returns></returns>
        private string  getLimitCarNo(string cardNo)
        {
            if (mComparison != null && mComparison.Count > 0)
            {
                if(mComparison.Contains(cardNo))
                {
                    return cardNo;
                }
                else
                {
                    return "非匹配卡号";
                }
            }
            else
            {
                return cardNo;
            }
        }
        /// <summary>
        /// 读卡操作
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        ResultEntity<ResultValEntity> ICard.Read(ReadParamEntity entity)
        {
            ResultValEntity entityVal = new ResultValEntity();
            var res = ResultEntity<ResultValEntity>.Default(entityVal,"");
            try
            {
                //寻卡
                var querResult = QueryCard();
                if (querResult.State != 1)
                {
                    return ResultEntity<ResultValEntity>.Error(entityVal,"IC卡设备 寻卡失败,错误:" + querResult.Message);
                }

                //密码验证
                var authResult = authentication((byte)entity.SectorNo);
                if (authResult.State !=1) {
                   return ResultEntity<ResultValEntity>.Error(entityVal, authResult.Message);
                }

                byte[] databuffer = new byte[32];
                string blockNo = (entity.SectorNo * 4 + entity.BlockNo).ToString();
                byte block = Convert.ToByte(blockNo);
                short result = -1;
                string data = string.Empty;
                bool IsGetData = false;

                //如果读卡失败则连续读三次
                for (int index = 0; index < 3; index++) 
                {
                    result = rf_read(icdev, block, databuffer);
                    if (result == 0)
                    {
                        data = mEncode.GetString(databuffer);
                        IsGetData = true;
                        break;
                    }
                }

                if(IsGetData)
                {
                    entityVal.val = data.Replace('\0',' ').Trim();
                    res = ResultEntity<ResultValEntity>.Success(entityVal, data);
                }
                else
                {
                    res = ResultEntity<ResultValEntity>.Error(entityVal, "IC卡设备 读卡失败");
                }
            }
            catch (Exception ex)
            {
                res = ResultEntity<ResultValEntity>.Error(entityVal, "IC卡设备 读卡异常,异常信息:"+ex.Message+ex.StackTrace);
            }
            return res;
        }

        /// <summary>
        ///  //验证密码
        /// </summary>
        /// <param name="sector">扇区号</param>
        /// <returns>失败、成功、异常</returns>
        public ResultEntity authentication(byte sector)
        {
            var res = ResultEntity.Default();
            try
            {
                short result = rf_authentication(icdev, 0, sector);
                if (result != 0)
                {
                    res = ResultEntity.Error("IC卡设备 验证密码失败");
                }
                else
                {
                    res = ResultEntity.Success("IC卡设备 验证密码成功");
                }
            }
            catch (Exception ex)
            {
                res = ResultEntity.Error("IC卡设备 验证密码异常，异常信息:"+ex.Message+ex.StackTrace);
            }
            return res;
        }

        /// <summary>
        /// 写卡
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        ResultEntity ICard.Write(WriteParamEntity entity)
        {
            var res = ResultEntity.Default();
            try
            {
                //寻卡
                var querResult = QueryCard();
                if (querResult.State != 1)
                {
                    return ResultEntity.Error("IC卡设备 寻卡失败,错误:" + querResult.Message);
                }

                //密码验证
                var authResult = authentication((byte)entity.SectorNo);
                if (authResult.State != 1)
                {
                    return ResultEntity.Error(authResult.Message);
                }

                byte[] lastData = new byte[32];
                byte[] data = mEncode.GetBytes(entity.Value);
                for (int index = 0; index < 32; index++)
                {
                    if (index < data.Length)
                    {
                        lastData[index] = data[index];
                    }
                    else
                    {
                        lastData[index] = (byte)'\0';
                    }
                }

                if (entity.BlockNo == 3)
                {
                    res = ResultEntity.Error("IC卡设备 写卡失败，原因 每个扇区3块不允许写数据");
                }
                else
                {
                    int block = entity.SectorNo * 4 + entity.BlockNo;
                    short result = rf_write(icdev, (byte)block, lastData);
                    if (result != 0)
                    {
                        res = ResultEntity.Error("IC卡设备 写卡失败");
                    }
                    else
                    {
                        res = ResultEntity.Success("块3不允许写数据");
                    }
                }
            }
            catch (Exception ex)
            {
                res = ResultEntity.Error("IC卡设备 写卡异常，异常信息:"+ex.Message+","+ex.StackTrace);
            }
            return res;
        }

        /// <summary>
        /// 清卡操作
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public ResultEntity Clear(ClearParamEntity entity)
        {
            var result = ResultEntity.Default();
            try
            {
                byte[] lastData = new byte[32];
                for (int index = 0; index < 32; index++)
                {
                    lastData[index] = (byte)'\0';
                }

                if (entity.BlockNo == 3)
                {
                    return ResultEntity.Error("IC卡设备 ，清卡失败，原因每个扇区的3块为控制块不允许此操作"); 
                }

                //寻卡
                var querResult = QueryCard();
                if (querResult.State != 1)
                {
                    return ResultEntity.Error("IC卡设备 寻卡失败,错误:" + querResult.Message);
                }

                //验证密码
                authentication((byte)entity.SectorNo); 

                int block = entity.SectorNo * 4 + entity.BlockNo;
                short res = rf_write(icdev, (byte)block, lastData);
                if (res == 0)
                {
                    result =  ResultEntity.Success("IC卡设备，清卡成功!");
                }
                else
                {
                    result = ResultEntity.Error("IC卡设备，清卡失败!");
                }
            }
            catch (Exception ex)
            {
                result = ResultEntity.Error("IC卡设备，清卡异常,异常信息:"+ex.Message+","+ex.StackTrace);
            }

            return result;
        }


        /// <summary>
        /// 寻卡
        /// </summary>
        /// <returns></returns>
        private ResultEntity QueryCard()
        {
            ResultEntity res = ResultEntity.Default();
            short val = rf_card(icdev, (byte)1, snr);
            rf_beep(icdev, 25);
            if (val != 0)
            {
                return ResultEntity.Success("寻卡成功!");
            }
            else
            {
                return ResultEntity.Success("寻卡失败，错误代码:"+val);
            }
        }

        /// <summary>
        /// 设置卡号
        /// </summary>
        /// <param name="cardNos">比对集合</param>
        public void SetComparison(List<string> cardNos)
        {
            if(cardNos != null)
            {
                mComparison = cardNos;
            }
        }
    }
}


